package vip.liux.backend.infrastructure.message;

import org.springframework.core.log.LogMessage;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import vip.liux.backend.infrastructure.message.MessageRecord.MessageStatus;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;

public class JdbcMessageRecordRepositoryImpl extends JdbcDaoSupport implements MessageRecordRepository {

    // SQL 语句
    private static final String INSERT_SQL =
            "INSERT INTO message_record (message_id, biz_id, message_status, retry_count, " +
                    "next_retry_time, message_type, message_content, source_system, target_system) " +
                    "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";

    private static final String UPDATE_SQL =
            "UPDATE message_record SET message_status = ?, error_message = ?, updated_time = CURRENT_TIMESTAMP " +
                    "WHERE message_id = ?";

    private static final String RETRY_SQL =
            "UPDATE message_record SET retry_count = retry_count + 1, next_retry_time = ?, " +
                    "error_message = ?, message_status = ?, updated_time = CURRENT_TIMESTAMP " +
                    "WHERE message_id = ?";

    private static final String SELECT_SQL =
            "SELECT * FROM message_record WHERE message_id = ?";


    @Override
    public void createNewMessageRecord(MessageRecord messageRecord) {
        getJdbcTemplate().update(INSERT_SQL,
                messageRecord.getMessageId(),
                messageRecord.getBizId(),
                messageRecord.getMessageStatus(),
                messageRecord.getRetryCount(),
                messageRecord.getNextRetryTime(),
                messageRecord.getMessageType(),
                messageRecord.getMessageContent(),
                messageRecord.getSourceSystem(),
                messageRecord.getTargetSystem()
        );
    }

    @Override
    public void updateMessageRecord(String messageId, MessageStatus status, String errorMessage) {
        getJdbcTemplate().update(UPDATE_SQL,
                status.ordinal(),
                errorMessage,
                messageId
        );
    }

    @Override
    public void retryMessageRecord(String messageId, int retryCount, String errorMessage) {
        LocalDateTime nextRetryTime = calculateNextRetryTime(retryCount); // 根据重试策略计算下次时间
        getJdbcTemplate().update(RETRY_SQL,
                nextRetryTime,
                errorMessage,
                MessageStatus.RETRIED.ordinal(),
                messageId
        );
    }

    @Override
    public MessageRecord getMessageRecord(String messageId) {
        try {
            return getJdbcTemplate().queryForObject(
                    SELECT_SQL,
                    new MessageRecordRowMapper(),
                    messageId
            );
        } catch (EmptyResultDataAccessException ex) {
            this.logger.debug(LogMessage.format("No results found for message ID '%s'.", messageId), ex);
        } catch (IncorrectResultSizeDataAccessException ex) {
            this.logger.error(LogMessage.format(
                    "Multiple results found for message ID '%s'. Expected a unique result.", messageId), ex);
        } catch (DataAccessException ex) {
            this.logger.error(LogMessage.format("Failed to load message record for message ID '%s'.", messageId), ex);
        }
        return null;
    }

    // 计算下次重试时间（示例：指数退避）
    private LocalDateTime calculateNextRetryTime(int retryCount) {
        long delaySeconds = (long) Math.pow(2, retryCount) * 5; // 5s, 10s, 20s...
        return LocalDateTime.now().plusSeconds(delaySeconds);
    }

    // 结果集映射器
    private static class MessageRecordRowMapper implements RowMapper<MessageRecord> {
        @Override
        public MessageRecord mapRow(ResultSet rs, int rowNum) throws SQLException {
            MessageRecord record = new MessageRecord();
            record.setMessageId(rs.getLong("message_id"));
            record.setBizId(rs.getString("biz_id"));
            record.setMessageStatus(rs.getInt("message_status"));
            record.setRetryCount(rs.getInt("retry_count"));
            record.setNextRetryTime(rs.getObject("next_retry_time", LocalDateTime.class));
            record.setMessageType(rs.getString("message_type"));
            record.setMessageContent(rs.getString("message_content"));
            record.setSourceSystem(rs.getString("source_system"));
            record.setTargetSystem(rs.getString("target_system"));
            record.setCreatedTime(rs.getObject("created_time", LocalDateTime.class));
            record.setUpdatedTime(rs.getObject("updated_time", LocalDateTime.class));
            record.setErrorMessage(rs.getString("error_message"));
            return record;
        }
    }
}